#include "DataType.h"

////////////////
// WCharArray
////////////////
WTextDumpData::WTextDumpData(void)
{
	_initizlie();
}

WTextDumpData::WTextDumpData(const WTextDumpData& clsObject)
{
	_initizlie();
    if(NULL != clsObject.Array() && (0 < clsObject.Size()))
	{
		_setArrayData(clsObject.Array(), clsObject.Size());
	}
}

WTextDumpData::~WTextDumpData(void)
{
	_releaseArray(m_pArray);
}

void WTextDumpData::_initizlie(void)
{
	m_pArray = NULL;
	m_sSize = 0;
}

wchar_t* WTextDumpData::_heapArray(size_t sSize)
{
	wchar_t*		pNewArray = NULL;

	if(sSize > 0)
	{
		pNewArray = new wchar_t[sSize];
		if(NULL != pNewArray)
		{
            memset(pNewArray, 0x00, sizeof(wchar_t)*sSize);
		}
	}

	return pNewArray;
}

void WTextDumpData::_releaseArray(wchar_t* pSource)
{
	if(NULL != pSource)
	{
		delete pSource;
	}
}

void WTextDumpData::_setArrayData(const wchar_t* pSource, size_t sSize)
{
	// Set new data.
	if(NULL != pSource)
	{
		m_pArray = _heapArray(sSize);
		if(NULL != m_pArray)
		{
			memcpy(m_pArray, pSource, sizeof(wchar_t)*sSize);
			m_sSize = sSize;
		}
	}
}

void WTextDumpData::_resizeArray(size_t sNewSize, bool bKeepData)
{
	wchar_t*		pNewArray;

	if(sNewSize != m_sSize)
	{
		pNewArray = _heapArray(sNewSize);
		if(NULL != pNewArray)
		{
            if(true == bKeepData)
			{
                memcpy(pNewArray, m_pArray, sizeof(wchar_t)*(m_sSize>sNewSize?sNewSize:m_sSize));
			}
			m_sSize = sNewSize;
		}
	}
}

wchar_t* WTextDumpData::Array(void) const
{
	return m_pArray;
}

size_t WTextDumpData::Size(void) const
{
	return m_sSize;
}

void WTextDumpData::Set(const wchar_t* pSource, size_t sSize)
{
	// Release existed data.
	if(NULL != m_pArray)
	{
		_releaseArray(m_pArray);
		m_pArray = NULL;
		m_sSize = 0;
	}

	_setArrayData(pSource, sSize);
}

size_t WTextDumpData::IndexOf(wchar_t cCode)
{
	size_t sReturnIndex = INCALID_CHAR_INDEX;

	for(size_t sIdx=0; sIdx<m_sSize; sIdx++)
	{
        if(cCode == *(m_pArray+sIdx))
		{
			sReturnIndex = sIdx;
			break;
		}
	}

	return sReturnIndex;
}

void WTextDumpData::RemoveDuplicate(void)
{
	wchar_t*		pcProc = m_pArray;
	wchar_t*		pcSrc = m_pArray;
	wchar_t*		pcDest = m_pArray;

	// Skip head invisible characters
	while((*pcSrc) < 0x20)
	{
		pcSrc++;
	}
	if(pcSrc != m_pArray)
	{
		*m_pArray = *pcSrc;
	}

	// Remove duplicate char.
	while((((size_t)pcProc-(size_t)m_pArray)/(sizeof(wchar_t))) < m_sSize)
	{
		pcSrc = pcProc+1;
		pcDest = pcProc+1;
        while((((size_t)pcSrc-(size_t)m_pArray)/(sizeof(wchar_t))) < m_sSize)
		{
			if((*pcProc == *pcSrc) || (*pcSrc < 0x20))
			{
				pcSrc++;
			}
			else
			{
				*pcDest++ = *pcSrc++;
			}
		}
		pcProc++;
		m_sSize = pcDest-m_pArray;
	}

	_resizeArray(m_sSize);
}

void WTextDumpData::Sort(void)
{
	wchar_t		cSwapCode;

	// Only run when string length is greater then 1.
	if(m_sSize > 1)
	{
		for(int iChIdx=m_sSize; iChIdx>0; iChIdx--)
		{
			for(int iSwpIdx=1; iSwpIdx<iChIdx; iSwpIdx++)
			{
				if(*(m_pArray+iSwpIdx-1) > *(m_pArray+iSwpIdx))
				{
					cSwapCode = *(m_pArray+iSwpIdx-1);
					*(m_pArray+iSwpIdx-1) = *(m_pArray+iSwpIdx);
					*(m_pArray+iSwpIdx) = cSwapCode;
				}
			}
		}
	}
}

wxString WTextDumpData::ToString(void) const
{
	wxString strNewString = wxEmptyString;
	strNewString.Append(m_pArray, m_sSize);
	return strNewString;
}

wchar_t WTextDumpData::GetChar(size_t sIndex)
{
	return *(m_pArray+sIndex);
}
////////////////
// DumpTextData
////////////////
DumpTextData::DumpTextData(void)
{
	_initialize();
	SetString(wxEmptyString);
}

DumpTextData::DumpTextData(const wxString& strText)
{
	_initialize();
	SetString(strText);
}

DumpTextData::~DumpTextData(void)
{
	delete m_pclsHalfWidthCharArray;
	delete m_pclsFullWidthCharArray;
	delete m_pclsCharArray;
}

void DumpTextData::_initialize(void)
{
	m_pclsHalfWidthCharArray = new WTextDumpData();
	m_pclsFullWidthCharArray = new WTextDumpData();
	m_pclsCharArray = new WTextDumpData();
}

void DumpTextData::_sort(void)
{
	if(m_pclsCharArray->Size() > 0)
	{
		size_t sIdx=0;

		m_pclsCharArray->Sort();
		while((sIdx<m_pclsCharArray->Size()) && (m_pclsCharArray->GetChar(sIdx) < 0x7F))
		{
			sIdx++;
		}

        // Only full width character (ASCII).
        if(0 == sIdx)
		{
            m_pclsFullWidthCharArray->Set(m_pclsCharArray->Array(), m_pclsCharArray->Size());
		}
		// Only half width character.
		else if(sIdx >= m_pclsCharArray->Size())
		{
			m_pclsHalfWidthCharArray->Set(m_pclsCharArray->Array(), m_pclsCharArray->Size());
		}
		else
		{
			m_pclsHalfWidthCharArray->Set(m_pclsCharArray->Array(), sIdx);
			m_pclsFullWidthCharArray->Set(m_pclsCharArray->Array()+sIdx, m_pclsCharArray->Size()-sIdx);
		}
	}
}

void DumpTextData::SetString(const wxString& strText)
{
	/* Check buffer */
    m_pclsCharArray->Set(strText.GetData().AsWChar(), strText.Length());
    if(m_pclsCharArray->Size() > 0)
	{
		m_pclsCharArray->RemoveDuplicate();
		_sort();
	}
}

void DumpTextData::GetAllCharacter(wxString& strOut)
{
	strOut = m_pclsCharArray->ToString();
}

wxString DumpTextData::GetAllCharacter(void)
{
	return m_pclsCharArray->ToString();
}

void DumpTextData::GetHalfWidthCharacter(wxString& strOut)
{
	strOut = m_pclsHalfWidthCharArray->ToString();
}

wxString DumpTextData::GetHalfWidthCharacter(void)
{
	return m_pclsHalfWidthCharArray->ToString();
}

void DumpTextData::GetFullWidthCharacter(wxString& strOut)
{
	strOut = m_pclsFullWidthCharArray->ToString();
}

wxString DumpTextData::GetFullWidthCharacter(void)
{
	return m_pclsFullWidthCharArray->ToString();
}


wchar_t DumpTextData::GetChar(size_t sIndex)
{
	return m_pclsCharArray->GetChar(sIndex);
}

size_t DumpTextData::GetIndex(wchar_t cCharCode)
{
	size_t			sReturnIdx;

	sReturnIdx = m_pclsCharArray->IndexOf(cCharCode);
	return sReturnIdx;
}

size_t DumpTextData::GetHalfCharIndex(wchar_t cCharCode, size_t sStartIndex)
{
	size_t		sIndex = INCALID_CHAR_INDEX;
	if((cCharCode >= 0x20) && (cCharCode <= 0x7F))
	{
		sIndex = m_pclsHalfWidthCharArray->IndexOf(cCharCode);
		sIndex = sStartIndex + sIndex;
	}
	return sIndex;
}

size_t DumpTextData::GetFullCharIndex(wchar_t cCharCode, size_t sStartIndex)
{
	size_t		sIndex = INCALID_CHAR_INDEX;
	if(cCharCode > 0x7F)
	{
		sIndex = m_pclsFullWidthCharArray->IndexOf(cCharCode);
		sIndex = sStartIndex + (sIndex * 2);
		sIndex = sIndex | 0x8000;
	}
	return sIndex;
}

wxString DumpTextData::GetTextEncode(const wxString& strText, bool bUseFullASCII)
{
	wxString	strReturn = wxEmptyString;
	wxString	strCharCode;
	wchar_t		cCharCode;
	//size_t		sCharIndex;

	if(strText.Length() > 0)
	{
		strReturn.Append(wxT("{\""));
		for(size_t sIdx=0; sIdx<strText.Length(); sIdx++)
		{
			cCharCode = strText.GetChar(sIdx);
			if(cCharCode > 0x7F)
			{
				strCharCode = _getIndexEncode(GetFullCharIndex(cCharCode, bUseFullASCII?(0x7F-0x20+1):m_pclsHalfWidthCharArray->Size()));
			}
			else
			{
				if(bUseFullASCII == true)
				{
					strCharCode = wxString(cCharCode);
				}
				else
				{
					strCharCode = _getIndexEncode(GetHalfCharIndex(cCharCode));
				}
			}
			//if(INCALID_CHAR_INDEX != sCharIndex)
			{
				strReturn.Append(strCharCode);
			}
		}
		strReturn.Append(wxT("\"}, "));
	}
	return strReturn;
}

wxString DumpTextData::_getIndexEncode(size_t sIndex)
{
	wxString			strReturn;

	if(sIndex <= 0x7F)
	{
		strReturn.Append(wxString::Format("\\x%02X", sIndex));
	}
	else if(sIndex<0xFFFF)
	{
		strReturn.Append(wxString::Format("\\x%02X\\x%02X", ((sIndex>>8)&0xFF), (sIndex&0xFF)));
	}

	return strReturn;
}
